/**
 * Copyright (c) 2015-2016 Nationz
 *
 * zhai.yuehui
 * 2016-6-23
 * 下午1:38:02
 */
/**zhai.yuehui
 * 2016-6-23
 * 下午1:38:02
 */
package com.cosw.sdkShanghaiCA;

import android.app.Application;
import android.util.Log;
import android.widget.Toast;
import com.cosw.util.Logz;
import com.cosw.util.StringUtil;
import com.nationz.sim.sdk.NationzSim;
import com.nationz.sim.sdk.NationzSimCallback;
import java.security.MessageDigest;

public class NzBleUtil implements NationzSimCallback {

  private static final String TAG = "NzBleUtil";
  private static NationzSim mNationzSim;
  private static Application mApp;

  private Object lock;
  private BleStateListener listener;
  private boolean hasConnected = false;
  private boolean hasReceiveConnectResp = false;

  private static NzBleUtil mNzBleUtil;

  private NzBleUtil(Application app) {
    mApp = app;
    mNationzSim = NationzSim.initialize(mApp, this);
    NationzSim.setSdkParams(true, true, 3 * 60);
    NationzSim.setConnectTimeout(30);
    if (mNationzSim == null) {
      Toast.makeText(mApp, "您的手机不支持低功耗蓝牙功能", Toast.LENGTH_SHORT).show();
    }
  }

  public static synchronized NzBleUtil getInstance(Application app) {
    if (mNzBleUtil == null) {
      mNzBleUtil = new NzBleUtil(app);
    }
    return mNzBleUtil;
  }

  protected int getNzBleState() {
    return NationzSim.getConnectionState();
  }

  protected void setListener(BleStateListener listener) {
    this.listener = listener;
  }

  protected void connect(String name, String pin, int timeout, BleStateListener listener) {
    if (mNationzSim != null) {
      hasConnected = false;
      hasReceiveConnectResp = false;
      setListener(listener);

      if (name == null || !name.startsWith("BLESIM")) {
        listener.onConnectFailed("Not a BleSimCard！");
        return;
      }

      NationzSim.setConnectTimeout(timeout);// onConnectionStateChange返回27的时间
      // Toast.makeText(mApp, "正在连接蓝牙卡，请稍候", Toast.LENGTH_LONG).show();
      mNationzSim.connect(name, pin);
    }
  }

  /**
   * 分散规则如下： 由设备名称分散而来，蓝牙名称为BLESIM445566;
   * 则由名称的后3字节计算其md5值，得到f4f9c475b8b417e53995ee1fe3c7e9ca
   * ，再取md5的前3字节f4f9c4，16054724，对该值对1000000取余 054724，作为PIN；
   */
  private String calculatePinByName(String name) {
    if (name.startsWith("BLESIM") && name.length() == 12) {
      MessageDigest md5 = null;
      try {
        md5 = MessageDigest.getInstance("MD5");
        byte[] scatter = StringUtil.hexStringToByteArray(name
            .substring(6));

        byte[] md5Bytes = md5.digest(scatter);
        Log.e("md5Bytes", StringUtil.byteArrayToHexString(md5Bytes));
        String str = StringUtil.byteArrayToHexString(md5Bytes, 0, 3);
        int value = Integer.parseInt(str, 16);
        value = value % 1000000;
        byte[] pin0 = StringUtil.int2ArrayInRadix10(value);
        byte[] pin = new byte[3];
        pin[0] = pin[1] = (byte) 0x00;
        if (pin0.length == 1) {
          pin[2] = pin0[0];
        } else if (pin0.length == 2) {
          pin[2] = pin0[1];
          pin[1] = pin0[0];
        } else {
          pin[2] = pin0[2];
          pin[1] = pin0[1];
          pin[0] = pin0[0];
        }

        return StringUtil.byteArrayToHexString(pin);
      } catch (Exception e) {
        System.out.println(e.toString());
        e.printStackTrace();
        return "";
      }
    }

    return null;
  }

  protected void connect(String name, int timeout, BleStateListener listener) {
    if (mNationzSim != null) {
      hasConnected = false;
      hasReceiveConnectResp = false;
      setListener(listener);

      if (name == null || !name.startsWith("BLESIM")) {
        listener.onConnectFailed("Not a BleSimCard！");
        return;
      }

      NationzSim.setConnectTimeout(timeout);// onConnectionStateChange返回27的时间
      // Toast.makeText(mApp, "正在连接蓝牙卡，请稍候", Toast.LENGTH_LONG).show();
      String pin = calculatePinByName(name);
      Log.e(name, pin);

      if (pin == null) {
        listener.onConnectFailed("not a ble card");
      } else {
        mNationzSim.connect(name, pin);
      }
    }
  }

  /**
   * 关闭 SDK,断开与蓝牙卡的连接。
   */
  protected void close() {
    if (mNationzSim != null) {
      mNationzSim.close();
    }
  }

  /**
   * 关闭 SDK,断开与蓝牙卡的连接,如果是 SDK 打开的蓝牙模块,则关闭。
   */
  protected void closeBle() {
    if (mNationzSim != null) {
      mNationzSim.closeBle();
    }
  }

  @Override
  public void onConnectionStateChange(int state) {
    // TODO Auto-generated method stub
    Logz.e("onConnectionStateChange:", String.valueOf(state));

    if (listener != null) {
      if (state == 16) {
        // 连接成功;
        hasConnected = true;
        listener.onConnectSuccess();
        Logz.e("onConnectSuccess", "onConnectSuccess");
      } else if (state == 17) {
        listener.onConnectFailed("连接失败！");
      } else if (state == (short) 0x18) {
        // 连接已断开;
        if (hasConnected) {
          listener.onConnectingLost();
        }

        hasConnected = false;
      } else if (state == 20) {
        if (!hasReceiveConnectResp) {
          listener.onConnectFailed("认证失败！");
          hasReceiveConnectResp = true;
        }
      } else if (state == 21) {
        listener.onConnectFailed("手机不支持 BLE！");
      } else if (state == 22) {
        listener.onConnectFailed("手机蓝牙未打开！");
      } else if (state == 27) {
        // 超时；
        if (mNationzSim != null) {
          mNationzSim.close();
        }

        if (!hasReceiveConnectResp) {
          listener.onConnectFailed("连接超时！");
          hasReceiveConnectResp = true;
        }
      }
    }
  }

  @Override
  @Deprecated
  public void onMsgWrite(int state) {
  }

  @Override
  @Deprecated
  public void onMsgBack(byte[] msgBack) {
  }

  @Override
  public void onMsgBack(String pacName, String appName) {
    Log.e(TAG, pacName + " " + appName + " 已连接");
    Toast.makeText(mApp, pacName + " " + appName + "已连接",
        Toast.LENGTH_SHORT).show();
  }

  protected byte[] transmitApdu(byte[] apdu) throws Exception {
    if (NationzSim.getConnectionState() == 16) {
      Log.e(TAG, "APDU req: " + StringUtil.byteArrayToHexString(apdu));
      byte[] res = mNationzSim.wirteSync(apdu);
      Log.e(TAG, "APDU resp: " + StringUtil.byteArrayToHexString(res));
      return res;
    } else {
      throw new Exception("connection lost!");
    }
  }

  protected byte[] transmitApdu(byte[] apdu, short off, short len)
      throws Exception {
    byte[] apduBuff = new byte[len];
    StringUtil.byteArrayCopy(apdu, off, apduBuff, (short) 0, len);
    return transmitApdu(apduBuff);
  }
}
